/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frreport_comm.c                                    */
/*  NOTE      = report_comm公用                                    */
/*  DATE      = 2014/12/23                                         */
/*******************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <json-c/json.h>

#include "frmem.h"
#include "frlog.h"
#include "frvar_field.h"

#include "frct_comm.h"
#include "frreport_comm.h"

//#define FRREPORT_COMM_OLD_INTERFACE    1

FR_STATIC int __frreport_body_l7_add_data_str(Frreport_body_data *p_st_body_data
                                            , char *p_key
                                            , const char *p_value
                                            , short s_flag_trunc);

FR_STATIC int __frreport_body_l7_add_data_long(Frreport_body_data *p_st_body_data
                                             , char *p_key
                                             , long l_value);

FR_STATIC int __frreport_body_l7_add_data_double(Frreport_body_data *p_st_body_data
                                               , char *p_key
                                               , double d_value);

Frreport_data* __frreport_data_new(Frreport_type em_type, Frreport_type_l7data em_type_l7data)
{
    Frreport_data* p_st_data=NULL;

    p_st_data = (Frreport_data*)frmalloc(sizeof(Frreport_data));
    if(p_st_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return NULL;
    }

    memset(p_st_data, 0x00, sizeof(Frreport_data));
    p_st_data->st_data_header.arr_version[0] = 0;
    p_st_data->st_data_header.arr_version[1] = 0x01;
    fruuid(p_st_data->st_data_header.arr_msg_id);
    p_st_data->st_data_header.c_flag_zip = 0;
    p_st_data->em_type = em_type;
    p_st_data->em_type_l7data = em_type_l7data;

    gettimeofday (&p_st_data->st_data_header.st_event_timestamp, NULL);
    frlist_header_init(&p_st_data->st_hdr_body);

    return p_st_data;
}

/*******************************************************************************
*  FUNC     :  body节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_node_free(Frlist_node *node)
{
    if(node == NULL || node->data==NULL)
        return;

    Frreport_body_data *p_st_field = (Frreport_body_data *)node->data;
    if(p_st_field)
        frreport_body_free(&p_st_field);

    if(p_st_field)
        frfree(p_st_field);
    return;
}

void frreport_data_free(Frreport_data** pp_st_report_data)
{
    Frreport_data *p_st_report_data=NULL;
    if(pp_st_report_data == NULL || *pp_st_report_data == NULL)
        return;

    p_st_report_data = *pp_st_report_data;
    frlist_remove_all(&p_st_report_data->st_hdr_body, __frreport_node_free);

    frfree(p_st_report_data);
    *pp_st_report_data = NULL;
    return;
}

int frreport_set_body_len(Frreport_data* p_st_report_data, unsigned long ul_body_len)
{
    if(p_st_report_data == NULL)
        return FR_FAIL;

    p_st_report_data->st_data_header.ul_body_len = ul_body_len;
    return FR_SUCC;
}

int frreport_set_agent_from(Frreport_data* p_st_report_data, const char *p_agent_from)
{
    if(p_st_report_data == NULL || p_agent_from == NULL)
        return FR_FAIL;
    snprintf(p_st_report_data->st_data_header.arr_agent_from, sizeof(p_st_report_data->st_data_header.arr_agent_from)
            , "%s", p_agent_from);
    return FR_SUCC;
}

Frreport_body_data* frreport_body_new_stat_l4_tcp( u_short ip_proto
                                                   , u_int dst_ip
                                                   , u_short dst_port
                                                   , unsigned long ul_tx_bytes
                                                   , unsigned long ul_rx_bytes
                                                   , unsigned long ul_conns
                                                   , unsigned long ul_acks
                                                   , unsigned long ul_resets
                                                   , unsigned long ul_zero_win)
{
    Frreport_body_data *p_st_body_data=NULL;

    p_st_body_data = (Frreport_body_data *)frmalloc(sizeof(Frreport_body_data));
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return NULL;
    }

    memset(p_st_body_data, 0x00, sizeof(Frreport_body_data));
    p_st_body_data->em_type = FRREPORT_TYPE_STAT_L4;
    p_st_body_data->un_data.st_stat_l4_tcp.ip_proto = ip_proto;
    p_st_body_data->un_data.st_stat_l4_tcp.dst_ip = dst_ip;
    p_st_body_data->un_data.st_stat_l4_tcp.dst_port = dst_port;

    p_st_body_data->un_data.st_stat_l4_tcp.ul_tx_bytes = ul_tx_bytes;
    p_st_body_data->un_data.st_stat_l4_tcp.ul_rx_bytes = ul_rx_bytes;
    p_st_body_data->un_data.st_stat_l4_tcp.ul_conns = ul_conns;
    p_st_body_data->un_data.st_stat_l4_tcp.ul_acks = ul_acks;
    p_st_body_data->un_data.st_stat_l4_tcp.ul_resets = ul_resets;
    p_st_body_data->un_data.st_stat_l4_tcp.ul_zero_win = ul_zero_win;

    return p_st_body_data;
}

Frreport_body_data* frreport_body_new_stat_port( u_short ip_proto
                                               , u_int dst_ip
                                               , u_short dst_port
                                               , unsigned long ul_tx_bytes
                                               , unsigned long ul_rx_bytes
                                               , unsigned long ul_tx_pkts
                                               , unsigned long ul_rx_pkts)
{
    Frreport_body_data *p_st_body_data=NULL;

    p_st_body_data = (Frreport_body_data *)frmalloc(sizeof(Frreport_body_data));
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return NULL;
    }

    memset(p_st_body_data, 0x00, sizeof(Frreport_body_data));
    p_st_body_data->em_type = FRREPORT_TYPE_STAT_PORT;
    p_st_body_data->un_data.st_stat_port.ip_proto = ip_proto;
    p_st_body_data->un_data.st_stat_port.dst_ip = dst_ip;
    p_st_body_data->un_data.st_stat_port.dst_port = dst_port;

    p_st_body_data->un_data.st_stat_port.ul_tx_bytes = ul_tx_bytes;
    p_st_body_data->un_data.st_stat_port.ul_rx_bytes = ul_rx_bytes;
    p_st_body_data->un_data.st_stat_port.ul_tx_pkts = ul_tx_pkts;
    p_st_body_data->un_data.st_stat_port.ul_rx_pkts = ul_rx_pkts;

    return p_st_body_data;
}

Frreport_body_data* frreport_body_new_stat_conn( u_int src_ip
                                               , u_int dst_ip
                                               , u_short dst_port
                                               , u_int   ui_conns
                                               , u_int   ui_refused
                                               , u_int   ui_reset
                                               , unsigned long ul_tx_bytes
                                               , unsigned long ul_rx_bytes)
{
    Frreport_body_data *p_st_body_data=NULL;

    p_st_body_data = (Frreport_body_data *)frmalloc(sizeof(Frreport_body_data));
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return NULL;
    }

    memset(p_st_body_data, 0x00, sizeof(Frreport_body_data));
    p_st_body_data->em_type = FRREPORT_TYPE_STAT_CONN;
    p_st_body_data->un_data.st_stat_conn.src_ip = src_ip;
    p_st_body_data->un_data.st_stat_conn.dst_ip = dst_ip;
    p_st_body_data->un_data.st_stat_conn.dst_port = dst_port;

    p_st_body_data->un_data.st_stat_conn.ui_conns = ui_conns;
    p_st_body_data->un_data.st_stat_conn.ui_refused = ui_refused;
    p_st_body_data->un_data.st_stat_conn.ui_reset = ui_reset;
    p_st_body_data->un_data.st_stat_conn.ul_tx_bytes = ul_tx_bytes;
    p_st_body_data->un_data.st_stat_conn.ul_rx_bytes = ul_rx_bytes;

    return p_st_body_data;
}

Frreport_body_data* frreport_body_new_l7(Conntrack *p_st_ct)
{
    Frreport_body_data *p_st_body_data=NULL;

    if(p_st_ct == NULL )
        return NULL;

    //连接方向不确定时,解析内容不上报
    if(frct_get_direct_known(p_st_ct) == FR_DIRECT_UNKNOWN )
        return NULL;
    //协议不确定时,不上报
    //if(p_st_ct->st_l7_analyzer.p_st_l7_module == NULL)
    //    return NULL;

    p_st_body_data = (Frreport_body_data *)frmalloc(sizeof(Frreport_body_data));
    if(p_st_body_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return NULL;
    }

    memset(p_st_body_data, 0x00, sizeof(Frreport_body_data));
    p_st_body_data->em_type = FRREPORT_TYPE_L7DATA;
    p_st_body_data->un_data.st_l7data.ip_proto = p_st_ct->ip_proto;
    if(p_st_ct->flg_has_master || p_st_ct->flg_chg_stat_ip)
    {
        //p_st_body_data->un_data.st_l7data.src_ip = p_st_ct->st_masterInfo.src_ip;
        //p_st_body_data->un_data.st_l7data.dst_ip = p_st_ct->st_masterInfo.dst_ip;
        p_st_body_data->un_data.st_l7data.src_ip = p_st_ct->src_ip;
        p_st_body_data->un_data.st_l7data.dst_ip = p_st_ct->dst_ip;
        p_st_body_data->un_data.st_l7data.src_port = p_st_ct->stat_src_port;
        p_st_body_data->un_data.st_l7data.dst_port = p_st_ct->stat_dst_port;
    }
    else
    {
        p_st_body_data->un_data.st_l7data.src_ip = p_st_ct->src_ip;
        p_st_body_data->un_data.st_l7data.dst_ip = p_st_ct->dst_ip;
        p_st_body_data->un_data.st_l7data.src_port = p_st_ct->src_port;
        p_st_body_data->un_data.st_l7data.dst_port = p_st_ct->dst_port;
    }
    //frwarn("stat_port %i->%i\n", p_st_body_data->un_data.st_l7data.src_port, p_st_body_data->un_data.st_l7data.dst_port);

    if(p_st_ct->st_l7_analyzer.p_st_l7_module)
        p_st_body_data->un_data.st_l7data.i_l7_proto = p_st_ct->st_l7_analyzer.p_st_l7_module->i_l7_proto;
    else
        p_st_body_data->un_data.st_l7data.i_l7_proto = APM_L7_UNKNOWN;

    frlist_header_init(&p_st_body_data->un_data.st_l7data.st_hdr_comm);
    frlist_header_init(&p_st_body_data->un_data.st_l7data.st_hdr_req);
    frlist_header_init(&p_st_body_data->un_data.st_l7data.st_hdr_resp);
    frlist_header_init(&p_st_body_data->un_data.st_l7data.st_hdr_mq);

    return p_st_body_data;
}

int  frreport_body_l7_get_l7module(Frreport_body_data *p_st_body_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA )
        return APM_L7_UNKNOWN;

    return p_st_body_data->un_data.st_l7data.i_l7_proto;
}

int  frreport_body_l7_set_l7module(Frreport_body_data *p_st_body_data, int i_l7_proto)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA )
        return FR_FAIL;

    p_st_body_data->un_data.st_l7data.i_l7_proto = i_l7_proto;
    return FR_SUCC;
}

//int  frreport_body_l7_datatype(Frreport_body_data *p_st_body_data, int i_flag_request)
//{
//    if(p_st_body_data == NULL || (i_flag_request != FR_YES && i_flag_request != FR_NO) )
//        return FR_FAIL;
//
//    p_st_body_data->un_data.st_l7data.i_flag_request = i_flag_request;
//    return FR_SUCC;
//}

/*******************************************************************************
*  FUNC     :  克隆Frreport_body_data
*  ARGS     :  p_st_body_data       (Frreport_body_data *)
*  RTN      :  Frreport_body_data *;失败 NULL
*  NOTE     :
*******************************************************************************/
//Frreport_body_data *frreport_data_clone(Frreport_body_data *p_st_body_data)
//{
//    Frreport_body_data *p_st_body_data_clone=NULL;
//    Frlist_node *p_st_node=NULL, *p_st_node_clone=NULL;
//    Frvar_field *p_st_field_org = NULL, *p_st_field_clone=NULL;
//
//    if(p_st_body_data == NULL)
//        return NULL;
//
//    p_st_body_data_clone = frmalloc(sizeof(Frreport_body_data));
//    if(p_st_body_data_clone == NULL)
//    {
//        FRLOG_ERROR_DETAIL("frmalloc err");
//        return NULL;
//    }
//    memcpy(p_st_body_data_clone, p_st_body_data, sizeof(Frreport_body_data));
//
//    if(p_st_body_data->em_type != FRREPORT_TYPE_L7DATA)
//        return p_st_body_data_clone;
//
//    frlist_header_init(&p_st_body_data_clone->un_data.st_l7data.st_hdr);
//    p_st_node = FRLIST_FIRST_NODE(&p_st_body_data->un_data.st_l7data.st_hdr);
//    while(p_st_node)
//    {
//        p_st_field_org =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node);
//        p_st_field_clone = frvarfield_clone(p_st_field_org);
//        if(p_st_field_clone)
//        {
//            p_st_node_clone = frlist_node_create(p_st_field_clone);
//            if(p_st_node_clone == NULL)
//                frvarfield_free(&p_st_field_clone);
//            else
//                frlist_push(&p_st_body_data_clone->un_data.st_l7data.st_hdr, p_st_node_clone);
//        }
//
//        p_st_node = FRLIST_NEXT_NODE(p_st_node);
//    }
//
//    return p_st_body_data_clone;
//}

Frlist_header* frreport_body_l7list_clone(Frreport_body_data *p_st_body_data, Frreport_type_list em_type_lst)
{
    Frlist_header *p_list_hdr=NULL;
    Frlist_node *p_st_node_org=NULL, *p_st_node_clone=NULL;
    Frvar_field *p_st_field_org = NULL, *p_st_field_clone=NULL;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || (em_type_lst < FRREPORT_TYPE_LIST_COMM || em_type_lst > FRREPORT_TYPE_LIST_MQ ) )
        return NULL;

    p_list_hdr = (Frlist_header *)frmalloc(sizeof(Frlist_header));
    if(p_list_hdr == NULL)
        return NULL;

    memset(p_list_hdr, 0x00, sizeof(Frlist_header));
    frlist_header_init(p_list_hdr);

    switch(em_type_lst)
    {
        case FRREPORT_TYPE_LIST_REQ:
            p_st_node_org = FRLIST_FIRST_NODE(&p_st_body_data->un_data.st_l7data.st_hdr_req);
            break;
        case FRREPORT_TYPE_LIST_RESP:
            p_st_node_org = FRLIST_FIRST_NODE(&p_st_body_data->un_data.st_l7data.st_hdr_resp);
            break;
        case FRREPORT_TYPE_LIST_MQ:
            p_st_node_org = FRLIST_FIRST_NODE(&p_st_body_data->un_data.st_l7data.st_hdr_mq);
            break;
        default:
            p_st_node_org = FRLIST_FIRST_NODE(&p_st_body_data->un_data.st_l7data.st_hdr_comm);
            break;
    }

    while(p_st_node_org)
    {
        p_st_field_org =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node_org);
        p_st_field_clone = frvarfield_clone(p_st_field_org);
        if(p_st_field_clone)
        {
            p_st_node_clone = frlist_node_create(p_st_field_clone);
            if(p_st_node_clone == NULL)
                frvarfield_free(&p_st_field_clone);
            else
                frlist_push(p_list_hdr, p_st_node_clone);
        }

        p_st_node_org = FRLIST_NEXT_NODE(p_st_node_org);
    }

    return p_list_hdr;
}

int frreport_body_l7list_set(Frreport_body_data *p_st_body_data, Frreport_type_list em_type_lst, Frlist_header **pp_hdr_append)
{
    Frlist_header *p_hdr_dst=NULL, *p_hdr_app=NULL;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || (em_type_lst < FRREPORT_TYPE_LIST_COMM || em_type_lst > FRREPORT_TYPE_LIST_MQ )
       || pp_hdr_append == NULL || *pp_hdr_append == NULL)
        return FR_FAIL;
    p_hdr_app = *pp_hdr_append;

    switch(em_type_lst)
    {
        case FRREPORT_TYPE_LIST_REQ:
            p_hdr_dst = &p_st_body_data->un_data.st_l7data.st_hdr_req;
            break;
        case FRREPORT_TYPE_LIST_RESP:
            p_hdr_dst = &p_st_body_data->un_data.st_l7data.st_hdr_resp;
            break;
        case FRREPORT_TYPE_LIST_MQ:
            p_hdr_dst = &p_st_body_data->un_data.st_l7data.st_hdr_mq;
            break;
        default:
            p_hdr_dst = &p_st_body_data->un_data.st_l7data.st_hdr_comm;
            break;
    }

    frlist_merge_header_top(p_hdr_dst, p_hdr_app);
    frfree(p_hdr_app);
    *pp_hdr_append = NULL;

    return FR_SUCC;
}
/*******************************************************************************
*  FUNC     :  body里的node节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_body_node_free(Frlist_node *node)
{
    if(node == NULL || node->data==NULL)
        return;

    Frvar_field *p_st_field = (Frvar_field *)node->data;
    if(p_st_field)
        frvarfield_free(&p_st_field);
    if(p_st_field)
        frfree(p_st_field);
    return;
}

void frreport_body_l7list_free(Frlist_header** pp_hdr)
{
    Frlist_header *p_hdr=NULL;
    if(pp_hdr == NULL || *pp_hdr == NULL)
        return;
    p_hdr = *pp_hdr;

    frlist_destroy(p_hdr, __frreport_body_node_free);
    *pp_hdr = NULL;
    return;
}

void frreport_body_free(Frreport_body_data **pp_st_body_data)
{
    Frreport_body_data *p_st_body_data=NULL;
    if(pp_st_body_data == NULL || *pp_st_body_data == NULL)
        return;

    p_st_body_data = *pp_st_body_data;
    if(p_st_body_data->em_type == FRREPORT_TYPE_L7DATA)
    {
        frlist_remove_all(&p_st_body_data->un_data.st_l7data.st_hdr_comm, __frreport_body_node_free);
        frlist_remove_all(&p_st_body_data->un_data.st_l7data.st_hdr_req, __frreport_body_node_free);
        frlist_remove_all(&p_st_body_data->un_data.st_l7data.st_hdr_resp, __frreport_body_node_free);
        frlist_remove_all(&p_st_body_data->un_data.st_l7data.st_hdr_mq, __frreport_body_node_free);
    }

    frfree(p_st_body_data);
    *pp_st_body_data = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  Frreport_body_data里增加字符串数据(以list形式保存)
*  ARGS     :  p_st_body_data       (Frreport_body_data *)
*           :  p_key                (const char *)
*           :  p_value              (const char *)
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
#ifdef FRREPORT_COMM_OLD_INTERFACE
FR_STATIC int __frreport_body_l7_add_long(Frreport_body_data *p_st_body_data, const char *p_key, const char *p_value)
{
    char *p_key_new=NULL;
    unsigned int ui_len=0;
    int i_ret=0;
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0'
       || p_value == NULL)
        return FR_FAIL;

    ui_len = strlen(p_key) + 3;
    p_key_new = frmalloc(ui_len);
    if(p_key_new == NULL)
        return FR_FAIL;
    snprintf(p_key_new, ui_len, "%s.l", p_key);
    i_ret = __frreport_body_l7_add_data_str(p_st_body_data, p_key_new, p_value, FR_NO);
    if(i_ret == FR_FAIL)
        frfree(p_key_new);

    return i_ret;
}

#else

FR_STATIC int __frreport_body_l7_add_long(Frreport_body_data *p_st_body_data, const char *p_key, long l_value)
{
    char *p_key_new=NULL;
    unsigned int ui_len=0;
    int i_ret=0;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    ui_len = strlen(p_key) + 3;
    p_key_new = (char *)frmalloc(ui_len);
    if(p_key_new == NULL)
        return FR_FAIL;
    snprintf(p_key_new, ui_len, "%s.%lu", p_key, sizeof(long));
    i_ret = __frreport_body_l7_add_data_long(p_st_body_data, p_key_new, l_value);
    if(i_ret == FR_FAIL)
        frfree(p_key_new);

    return i_ret;
}
#endif

int  frreport_body_l7_add_timeval(Frreport_body_data *p_st_body_data, const char *p_key, struct timeval *p_st_timestamp)
{
    char *p_key_new=NULL;
    unsigned int ui_len=0;
    unsigned long ul_time=0;
    int i_ret=0;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
        || p_key == NULL || *p_key == '\0'
        || p_st_timestamp == NULL)
        return FR_FAIL;

    ul_time = p_st_timestamp->tv_sec*1000 + (long) (p_st_timestamp->tv_usec/1000);

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%lu", ul_time);
    #endif

    ui_len = strlen(p_key) + 3;
    p_key_new = (char *)frmalloc(ui_len);
    if(p_key_new == NULL)
        return FR_FAIL;
    snprintf(p_key_new, ui_len, "%s.d", p_key);

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        i_ret = __frreport_body_l7_add_data_str(p_st_body_data, p_key_new, arr_data, FR_NO);
    #else
        i_ret = __frreport_body_l7_add_data_long(p_st_body_data, p_key_new, ul_time);
    #endif
    if(i_ret == FR_FAIL)
        frfree(p_key_new);

    return i_ret;
}

int  frreport_body_l7_add_int(Frreport_body_data *p_st_body_data, const char *p_key, int i_data)
{

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%d", i_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        return __frreport_body_l7_add_long(p_st_body_data, p_key, i_data);
    #endif
}

int  frreport_body_l7_add_uint(Frreport_body_data *p_st_body_data, const char *p_key, unsigned int ui_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%u", ui_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        return __frreport_body_l7_add_long(p_st_body_data, p_key, ui_data);
    #endif
}

int  frreport_body_l7_add_long(Frreport_body_data *p_st_body_data, const char *p_key, long l_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%ld", l_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        return __frreport_body_l7_add_long(p_st_body_data, p_key, l_data);
    #endif
}

int  frreport_body_l7_add_ulong(Frreport_body_data *p_st_body_data, const char *p_key, unsigned long ul_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%lu", ul_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        //unsigned long -> long. 会造成大数据变成负数
        return __frreport_body_l7_add_long(p_st_body_data, p_key, (long)ul_data);
    #endif
}

int  frreport_body_l7_add_float(Frreport_body_data *p_st_body_data, const char *p_key, float f_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%f", f_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        return frreport_body_l7_add_double(p_st_body_data, p_key, (double)f_data);
    #endif
}

int  frreport_body_l7_add_double(Frreport_body_data *p_st_body_data, const char *p_key, double d_data)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    #ifdef FRREPORT_COMM_OLD_INTERFACE
        char arr_data[30];
        snprintf(arr_data, sizeof(arr_data), "%f", d_data);
        return __frreport_body_l7_add_long(p_st_body_data, p_key, arr_data);
    #else
        char *p_key_new=NULL;
        unsigned int ui_len=0;
        int i_ret=0;

        ui_len = strlen(p_key) + 3;
        p_key_new = (char *)frmalloc(ui_len);
        if(p_key_new == NULL)
            return FR_FAIL;
        snprintf(p_key_new, ui_len, "%s.f", p_key);

        i_ret = __frreport_body_l7_add_data_double(p_st_body_data, p_key_new, d_data);
        if(i_ret == FR_FAIL)
            frfree(p_key_new);
        return i_ret;
    #endif
}

Frlist_header *frreport_body_l7_get_hdr(Frreport_body_data *p_st_body_data, const char *p_key)
{
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0' )
        return NULL;

    if(strncmp( p_key , APM_REPORT_KEY_REQ, strlen(APM_REPORT_KEY_REQ)) == 0)
        return &p_st_body_data->un_data.st_l7data.st_hdr_req;
    else if(strncmp( p_key , APM_REPORT_KEY_RESP, strlen(APM_REPORT_KEY_RESP)) == 0)
        return &p_st_body_data->un_data.st_l7data.st_hdr_resp;
    else if(strncmp( p_key , APM_REPORT_KEY_SUB, strlen(APM_REPORT_KEY_SUB)) == 0
            || strncmp( p_key , APM_REPORT_KEY_NOTIFY, strlen(APM_REPORT_KEY_NOTIFY)) == 0
            || strncmp( p_key , APM_REPORT_KEY_PUB, strlen(APM_REPORT_KEY_PUB)) == 0)
        return &p_st_body_data->un_data.st_l7data.st_hdr_mq;
    else
        return &p_st_body_data->un_data.st_l7data.st_hdr_comm;
}

int  frreport_body_l7_del_all(Frreport_body_data *p_st_body_data, const char *p_key)
{
    Frlist_header * p_lst_hdr=NULL;
    Frlist_node *p_st_node_do=NULL, *p_st_node_next=NULL;
    Frvar_field *p_st_field = NULL;
    char arr_key_name[256];
    int i_ret=FR_FAIL, i_key_len=0;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr==NULL)
        return FR_FAIL;

    snprintf(arr_key_name, sizeof(arr_key_name), "%s.", p_key);
    i_key_len = strlen(arr_key_name);
    p_st_node_do = FRLIST_FIRST_NODE(p_lst_hdr);
    while(p_st_node_do)
    {
        p_st_node_next = FRLIST_NEXT_NODE(p_st_node_do);
        p_st_field =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node_do);
        if(p_st_field == NULL || p_st_field->p_field_name == NULL)
        {
            p_st_node_do = p_st_node_next;
            continue;
        }
        if( p_st_field->p_field_name
            && strlen(p_st_field->p_field_name) == i_key_len+1
            && strncmp(p_st_field->p_field_name, arr_key_name, i_key_len) == 0
           )
        {
            frlist_node_free(p_lst_hdr, p_st_node_do, 1, __frreport_body_node_free);
            i_ret = FR_SUCC;
        }

        p_st_node_do = p_st_node_next;
    }

    return i_ret;
}

int  frreport_body_l7_del_index(Frreport_body_data *p_st_body_data, const char *p_key, unsigned int ui_index)
{
    Frlist_header * p_lst_hdr=NULL;
    Frlist_node *p_st_node_do=NULL, *p_st_node_next=NULL;
    Frvar_field *p_st_field = NULL;
    char arr_key_name[256];
    int i_ret=FR_FAIL, i_key_len=0;
    unsigned int ui_count=0;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr==NULL)
        return FR_FAIL;

    snprintf(arr_key_name, sizeof(arr_key_name), "%s.", p_key);
    i_key_len = strlen(arr_key_name);
    p_st_node_do = FRLIST_FIRST_NODE(p_lst_hdr);
    while(p_st_node_do)
    {
        p_st_node_next = FRLIST_NEXT_NODE(p_st_node_do);
        p_st_field =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node_do);
        if(p_st_field == NULL || p_st_field->p_field_name == NULL)
        {
            p_st_node_do = p_st_node_next;
            continue;
        }

        if( p_st_field->p_field_name
            && strlen(p_st_field->p_field_name) == i_key_len+1
            && strncmp(p_st_field->p_field_name, arr_key_name, i_key_len) == 0
           )
        {
            if( ui_count++ == ui_index)
            {
                frlist_node_free(p_lst_hdr, p_st_node_do, 1, __frreport_body_node_free);
                i_ret = FR_SUCC;
                break;
            }
        }

        p_st_node_do = p_st_node_next;
    }

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  Frreport_body_data里增加字符串数据(以list形式保存)
*  ARGS     :  p_st_body_data       (Frreport_body_data *)
*           :  p_key                (char *, FR_SUCC:函数内部直接使用该内存)
*           :  p_value              (const char *)
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frreport_body_l7_add_data_str(Frreport_body_data *p_st_body_data
                                            , char *p_key
                                            , const char *p_value
                                            , short s_flag_trunc)
{
    Frlist_header *p_lst_hdr=NULL;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0'
       || p_value == NULL)
        return FR_FAIL;

    p_st_field = frvarfield_str2(p_key, p_value, s_flag_trunc);
    if(p_st_field == NULL)
        return FR_FAIL;

    p_st_node = frlist_node_create(p_st_field);
    if(p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        return FR_FAIL;
    }

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr == NULL)
    {
        frvarfield_free(&p_st_field);
        frfree(p_st_node);
        return FR_FAIL;
    }
    frlist_push(p_lst_hdr, p_st_node);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  Frreport_body_data里增加字符串数据(以list形式保存)
*  ARGS     :  p_st_body_data       (Frreport_body_data *)
*           :  p_key                (char *, FR_SUCC:函数内部直接使用该内存)
*           :  l_value              (long)
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frreport_body_l7_add_data_long(Frreport_body_data *p_st_body_data
                                             , char *p_key
                                             , long l_value)
{
    Frlist_header *p_lst_hdr=NULL;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    p_st_field = frvarfield_long2(p_key, l_value);
    if(p_st_field == NULL)
        return FR_FAIL;

    p_st_node = frlist_node_create(p_st_field);
    if(p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        return FR_FAIL;
    }

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr == NULL)
    {
        frvarfield_free(&p_st_field);
        frfree(p_st_node);
        return FR_FAIL;
    }
    frlist_push(p_lst_hdr, p_st_node);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  Frreport_body_data里增加字符串数据(以list形式保存)
*  ARGS     :  p_st_body_data       (Frreport_body_data *)
*           :  p_key                (char *, FR_SUCC:函数内部直接使用该内存)
*           :  d_value              (double)
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frreport_body_l7_add_data_double(Frreport_body_data *p_st_body_data
                                               , char *p_key
                                               , double d_value)
{
    Frlist_header *p_lst_hdr=NULL;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0')
        return FR_FAIL;

    p_st_field = frvarfield_double2(p_key, d_value);
    if(p_st_field == NULL)
        return FR_FAIL;

    p_st_node = frlist_node_create(p_st_field);
    if(p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        return FR_FAIL;
    }

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr == NULL)
    {
        frvarfield_free(&p_st_field);
        frfree(p_st_node);
        return FR_FAIL;
    }
    frlist_push(p_lst_hdr, p_st_node);

    return FR_SUCC;
}

int  frreport_body_l7_add_str(Frreport_body_data *p_st_body_data, const char *p_key, const char *p_value)
{
    char *p_key_new=NULL;
    unsigned int ui_len=0;
    int i_ret=0;
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0'
       || p_value == NULL)
        return FR_FAIL;

    ui_len = strlen(p_key) + 3;
    p_key_new = (char *)frmalloc(ui_len);
    if(p_key_new == NULL)
        return FR_FAIL;
    snprintf(p_key_new, ui_len, "%s.s", p_key);
    i_ret = __frreport_body_l7_add_data_str(p_st_body_data, p_key_new, p_value, FR_NO);
    if(i_ret == FR_FAIL)
        frfree(p_key_new);

    return i_ret;
}

int  frreport_body_l7_add_str_limit(Frreport_body_data *p_st_body_data
                                  , const char *p_key
                                  , const char *p_value
                                  , unsigned int ui_limit_value_len)
{
    char *p_key_new=NULL, *p_value_limit=NULL;
    unsigned int ui_len_key=0, ui_len_value=0;
    int i_ret=0;
    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0'
       || p_value == NULL)
        return FR_FAIL;

    ui_len_key = strlen(p_key) + 3;
    p_key_new = (char *)frmalloc(ui_len_key);
    if(p_key_new == NULL)
        return FR_FAIL;

    ui_len_value = strlen(p_value);
    if(ui_limit_value_len < ui_len_value)
    {
        p_value_limit = (char *)frmalloc(ui_limit_value_len+1);
        if(p_value_limit == NULL)
            goto ERROR;
        memcpy(p_value_limit, p_value, ui_limit_value_len);
        p_value_limit[ui_limit_value_len] = '\0';

        snprintf(p_key_new, ui_len_key, "%s.t", p_key);
    }
    else
        snprintf(p_key_new, ui_len_key, "%s.s", p_key);

    if(p_value_limit)
    {
        i_ret = __frreport_body_l7_add_data_str(p_st_body_data, p_key_new, p_value_limit, FR_YES);
        frfree(p_value_limit);
    }
    else
        i_ret = __frreport_body_l7_add_data_str(p_st_body_data, p_key_new, p_value, FR_NO);
    if(i_ret == FR_FAIL)
        frfree(p_key_new);

    return i_ret;

ERROR:
    if(p_key_new)
        frfree(p_key_new);
    if(p_value_limit)
        frfree(p_value_limit);
    return FR_FAIL;
}

int  frreport_body_l7_add_bin(Frreport_body_data *p_st_body_data, const char *p_key, const char *p_value, unsigned int ui_len)
{
    Frlist_header *p_lst_hdr=NULL;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;
    char *p_key_new=NULL;
    int ui_len_key=0;

    if(p_st_body_data == NULL || p_st_body_data->em_type != FRREPORT_TYPE_L7DATA
       || p_key == NULL || *p_key == '\0'
       || ui_len < 0)
        return FR_FAIL;

    ui_len_key = strlen(p_key)+3;
    p_key_new = (char *)frmalloc(ui_len_key);
    if(p_key_new == NULL)
        return FR_FAIL;
    snprintf(p_key_new, ui_len_key, "%s.b", p_key);

    //p_st_field = frvarfield_bin(p_key, p_value, ui_len);
    if(p_value && ui_len > 0)
    {
        if(ui_len >= APM_REPORT_MAX)
            p_st_field = frvarfield_bin(p_key_new, p_value, APM_REPORT_MAX, FR_YES);
        else
            p_st_field = frvarfield_bin(p_key_new, p_value, ui_len, FR_NO);
    }
    else
        p_st_field = frvarfield_bin(p_key_new, "BINARY", strlen("BINARY"), FR_NO);
    if(p_st_field == NULL)
        goto ERROR;

    p_st_node = frlist_node_create(p_st_field);
    if(p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        goto ERROR;
    }

    p_lst_hdr = frreport_body_l7_get_hdr(p_st_body_data, p_key);
    if(p_lst_hdr == NULL)
    {
        frvarfield_free(&p_st_field);
        frfree(p_st_node);
        goto ERROR;
    }
    frlist_push(p_lst_hdr, p_st_node);
    if(p_key_new)
        frfree(p_key_new);

    return FR_SUCC;

ERROR:
    if(p_key_new)
        frfree(p_key_new);
    return FR_FAIL;
}

int  frreport_body_l7_add_connInfo(Frreport_body_data *p_st_body_data, Conntrack *p_st_ct)
{
    if(p_st_body_data == NULL || p_st_ct == NULL)
        return FR_FAIL;

    if(p_st_ct->arr_connection_id[0] != '\0')
        frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_CONN_ID, p_st_ct->arr_connection_id);

    frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_CONN_EST_TIMESTAMP, &p_st_ct->st_connection_established);
    if(p_st_ct->ip_proto == IPPROTO_TCP)
    {
        unsigned long ul_tmp = frtime_diff(&p_st_ct->st_connection_created, &p_st_ct->st_connection_established);
#ifdef FRDBG_COREDUMP
        //>10分钟
        if(ul_tmp > 600 * 1000000)
        {
            APM_COREDUMP;
        }
#endif
        //todo
        if(ul_tmp >= 1000000)
            ul_tmp = 0;
        frreport_body_l7_add_ulong(p_st_body_data, APM_REPORT_KEY_CONN_SYN_TIME_US, ul_tmp);
    }

    return FR_SUCC;
}

int frreport_data_add_body(Frreport_data *p_st_report_data, Frreport_body_data *p_st_body_data)
{
    Frlist_node *p_st_node = NULL;

    if(p_st_report_data == NULL || p_st_body_data == NULL)
        return FR_FAIL;

    p_st_node = frlist_node_create(p_st_body_data);
    if(p_st_node == NULL)
        return FR_FAIL;

    frlist_push(&p_st_report_data->st_hdr_body, p_st_node);
    return FR_SUCC;
}


Frreport_data *frreport_update_create(Conntrack *p_st_ct, const char *p_update_event, const char *p_msg, struct timeval *p_st_timestamp)
{
    Frreport_data *p_st_report_data=NULL;
    Frreport_body_data *p_st_report_body=NULL;

    if(p_st_ct == NULL || p_update_event == NULL || *p_update_event == '\0' || p_st_timestamp == NULL)
        return NULL;

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_UPDATE);
    if(p_st_report_data == NULL)
        return NULL;

    p_st_report_body = frreport_body_new_l7(p_st_ct);
    if(p_st_report_body == NULL)
        goto FAIL;

    frreport_body_l7_add_connInfo(p_st_report_body, p_st_ct);
    frreport_body_l7_add_str(p_st_report_body, APM_REPORT_KEY_UPDATE_EVENT, p_update_event);
    frreport_body_l7_add_str(p_st_report_body, APM_REPORT_KEY_UPDATE_MSG, p_msg);
    frreport_body_l7_add_timeval(p_st_report_body, APM_REPORT_KEY_UPDATE_TIMESTAMP, p_st_timestamp);

    frreport_data_add_body(p_st_report_data, p_st_report_body);
    return p_st_report_data;

FAIL:
    frreport_data_free(&p_st_report_data);
    return NULL;
}

/*******************************************************************************
*  FUNC     :  获取指定链表
*  ARGS     :  p_st_hash_report     (Frhash_header *; 保存Frreport_data)
*           :  ui_idx               (需要从hash里获取的连表位置)
*  RTN      :  Frlist_header *
*  NOTE     :
*******************************************************************************/
FR_STATIC Frlist_header *__frreport_get_list_hdr(Frhash_header  *p_st_hash_report  //保存Frreport_data
                                               , unsigned int ui_idx )
{
    Frlist_header *p_st_lst_hdr_tmp = NULL;
    int i_loop=0;

    if(p_st_hash_report == NULL
       || (ui_idx != APM_REPORT_TYPE_L7DATA && ui_idx != APM_REPORT_TYPE_OTHER) )
        return NULL;

    FRHASH_LOOP(i_loop, p_st_hash_report, p_st_lst_hdr_tmp)
    {
        if(ui_idx == i_loop)
            return p_st_lst_hdr_tmp;
    }

    return NULL;
}

int frreport_data_hash(Frhash_header *p_st_hash_report, Frreport_data *p_st_report_data)
{
    Frlist_header *p_lst_hdr = NULL;
    Frlist_node *p_st_node = NULL;

    if(p_st_hash_report == NULL || p_st_report_data == NULL)
        return FR_FAIL;

    //获取数据保存list
    p_lst_hdr = __frreport_get_list_hdr(p_st_hash_report, APM_REPORT_TYPE_L7DATA);
    if(p_lst_hdr == NULL)
    {
        FRLOG_WARN_DETAIL("__frreport_get_list_hdr NULL");
        return FR_FAIL;
    }

    p_st_node = frlist_node_create(p_st_report_data);
    if(p_st_node == NULL)
        return FR_FAIL;

    frlist_push(p_lst_hdr, p_st_node);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  上报头数据的出力
*  ARGS     :  p_st_hdr     (Frreport_header *)
*           :  p_st_json    (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_header(Frreport_type em_type, Frreport_type_l7data em_type_l7data, Frreport_header *p_st_hdr
                                      , json_object *p_st_json)
{
    char arr_buff[20];

    if(p_st_hdr == NULL || p_st_json == NULL)
        return;
    json_object_object_add(p_st_json, "magic number", json_object_new_string(APM_REPORT_MAGIC_NUMBER));
    snprintf(arr_buff, sizeof(arr_buff), "0x%02x%02x", p_st_hdr->arr_version[0], p_st_hdr->arr_version[1]);
    json_object_object_add(p_st_json, "version", json_object_new_string(arr_buff));
    //json_object_object_add(p_st_json, json_object_new_int64(p_st_hdr->ul_body_len));
    json_object_object_add(p_st_json, "msg_id", json_object_new_string(p_st_hdr->arr_msg_id));
    json_object_object_add(p_st_json, "agent_from",json_object_new_string(p_st_hdr->arr_agent_from));
    json_object_object_add(p_st_json, "flag_zip", json_object_new_int(p_st_hdr->c_flag_zip));
    switch(em_type)
    {
        case FRREPORT_TYPE_STAT_PORT:
            json_object_object_add(p_st_json, "em_type", json_object_new_string("PORT"));
            break;
        case FRREPORT_TYPE_STAT_CONN:
            json_object_object_add(p_st_json, "em_type", json_object_new_string("STAT"));
            break;
        case FRREPORT_TYPE_L7DATA:
            if(em_type_l7data == FRREPORT_TYPE_L7DATA_REQ)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("REQ "));
            else if(em_type_l7data == FRREPORT_TYPE_L7DATA_RESP)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("RESP"));
            else if(em_type_l7data == FRREPORT_TYPE_L7DATA_PUB)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("PUB "));
            else if(em_type_l7data == FRREPORT_TYPE_L7DATA_SUB)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("SUB "));
            else if(em_type_l7data == FRREPORT_TYPE_L7DATA_NOTIFY)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("NIFY"));
            else if(em_type_l7data == FRREPORT_TYPE_L7DATA_UPDATE)
                json_object_object_add(p_st_json, "em_type", json_object_new_string("UPDT"));
            break;
        case FRREPORT_TYPE_STAT_L4:
            json_object_object_add(p_st_json, "em_type", json_object_new_string("L4IF"));
            break;
        default:
            json_object_object_add(p_st_json, "em_type", json_object_new_string("UNKNOWN"));
            break;
    }

    json_object *p_array=json_object_new_array();
    json_object_array_add(p_array,json_object_new_int64(p_st_hdr->st_event_timestamp.tv_sec));
    json_object_array_add(p_array,json_object_new_int64(p_st_hdr->st_event_timestamp.tv_usec));
    json_object_object_add(p_st_json,"event_timestamp",p_array);

    return;
}

/*******************************************************************************
*  FUNC     :  端口统计信息的出力
*  ARGS     :  p_st_hdr     (Frreport_header *)
*           :  p_st_json    (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_stat_tcp(Frreport_stat_l4_tcp  *p_report_stat_l4_tcp, json_object *p_obj_array)
{
    char arr_buff[64];
    json_object *p_obj_item=NULL;

    if(p_report_stat_l4_tcp == NULL || p_obj_array == NULL)
        return ;

    p_obj_item = json_object_new_object();
    if(p_obj_item == NULL)
        return;

    //json_object_object_add(p_obj_item, "em_type", json_object_new_string("TCP "));

    json_object_object_add(p_obj_item, "ip_proto", json_object_new_int(p_report_stat_l4_tcp->ip_proto));
    sprintf(arr_buff, "%s", int_ntoa (p_report_stat_l4_tcp->dst_ip));
    json_object_object_add(p_obj_item, "dst_ip", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%i", p_report_stat_l4_tcp->dst_port);
    json_object_object_add(p_obj_item, "dst_port", json_object_new_string(arr_buff));

    json_object_object_add(p_obj_item, "tx_bytes", json_object_new_int64(p_report_stat_l4_tcp->ul_tx_bytes));
    json_object_object_add(p_obj_item, "rx_bytes", json_object_new_int64(p_report_stat_l4_tcp->ul_rx_bytes));
    json_object_object_add(p_obj_item, "conns", json_object_new_int64(p_report_stat_l4_tcp->ul_conns));
    json_object_object_add(p_obj_item, "acks", json_object_new_int64(p_report_stat_l4_tcp->ul_acks));
    json_object_object_add(p_obj_item, "resets", json_object_new_int64(p_report_stat_l4_tcp->ul_resets));
    json_object_object_add(p_obj_item, "zero_win", json_object_new_int64(p_report_stat_l4_tcp->ul_zero_win));

    json_object_array_add(p_obj_array, p_obj_item);
    return;
}

/*******************************************************************************
*  FUNC     :  端口统计信息的出力
*  ARGS     :  p_st_hdr     (Frreport_header *)
*           :  p_st_json    (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_stat_port(Frreport_stat_port  *p_st_stat_port, json_object *p_obj_array)
{
    char arr_buff[64];
    json_object *p_obj_item=NULL;

    if(p_st_stat_port == NULL || p_obj_array == NULL)
        return ;

    p_obj_item = json_object_new_object();
    if(p_obj_item == NULL)
        return;

    json_object_object_add(p_obj_item, "em_type", json_object_new_string("PORT"));

    json_object_object_add(p_obj_item, "ip_proto", json_object_new_int(p_st_stat_port->ip_proto));
    sprintf(arr_buff, "%s", int_ntoa (p_st_stat_port->dst_ip));
    json_object_object_add(p_obj_item, "dst_ip", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%i", p_st_stat_port->dst_port);
    json_object_object_add(p_obj_item, "dst_port", json_object_new_string(arr_buff));

    json_object_object_add(p_obj_item, "tx_bytes", json_object_new_int64(p_st_stat_port->ul_tx_bytes));
    json_object_object_add(p_obj_item, "rx_bytes", json_object_new_int64(p_st_stat_port->ul_rx_bytes));
    json_object_object_add(p_obj_item, "tx_pkts", json_object_new_int64(p_st_stat_port->ul_tx_pkts));
    json_object_object_add(p_obj_item, "rx_pkts", json_object_new_int64(p_st_stat_port->ul_rx_pkts));

    json_object_array_add(p_obj_array, p_obj_item);
    return;
}

/*******************************************************************************
*  FUNC     :  连接数统计信息的出力
*  ARGS     :  p_st_hdr     (Frreport_header *)
*           :  p_st_json    (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_stat_conn(Frreport_stat_conn  *p_st_stat_conn, json_object *p_obj_array)
{
    char arr_buff[64];
    json_object *p_obj_item=NULL;

    if(p_st_stat_conn == NULL || p_obj_array == NULL)
        return ;

    p_obj_item = json_object_new_object();
    if(p_obj_item == NULL)
        return;

    json_object_object_add(p_obj_item, "em_type", json_object_new_string("STAT"));

    sprintf(arr_buff, "%s", int_ntoa (p_st_stat_conn->src_ip));
    json_object_object_add(p_obj_item, "src_ip", json_object_new_string(arr_buff));

    sprintf(arr_buff, "%s", int_ntoa (p_st_stat_conn->dst_ip));
    json_object_object_add(p_obj_item, "dst_ip", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%i", p_st_stat_conn->dst_port);
    json_object_object_add(p_obj_item, "dst_port", json_object_new_string(arr_buff));

    json_object_object_add(p_obj_item, "conns", json_object_new_int(p_st_stat_conn->ui_conns));
    json_object_object_add(p_obj_item, "refused", json_object_new_int(p_st_stat_conn->ui_refused));
    json_object_object_add(p_obj_item, "reset", json_object_new_int(p_st_stat_conn->ui_reset));
    json_object_object_add(p_obj_item, "tx_bytes", json_object_new_int64(p_st_stat_conn->ul_tx_bytes));
    json_object_object_add(p_obj_item, "rx_bytes", json_object_new_int64(p_st_stat_conn->ul_rx_bytes));

    json_object_array_add(p_obj_array, p_obj_item);
    return;
}

/*******************************************************************************
*  FUNC     :  json里增加string数据
*  ARGS     :  json             (json_object *)
*           :  key              (const char *)
*           :  val              (const char *)
*  RTN      :
*  NOTE     :  如果存在该key，则变成数组
*******************************************************************************/
FR_STATIC void __frreport_json_add_str(json_object *json, const char *p_key, const char *p_value)
{
    struct json_object *result = NULL;
    if(json == NULL ||  p_key == NULL || p_value == NULL)
        return;

    json_object_object_get_ex(json, p_key, &result);
    if(result == NULL)
    {
        json_object_object_add(json, p_key, json_object_new_string(p_value));
        return;
    }

    if( ! json_object_is_type(result, json_type_array)  )
    {
        json_object_get(result);
        json_object *tech=json_object_new_array();
        json_object_array_add(tech, result);
        json_object_array_add(tech,json_object_new_string(p_value));
        json_object_object_add(json, p_key,tech);
    }
    else
    {
        json_object_array_add(result,json_object_new_string(p_value));
    }

    return;
}

/*******************************************************************************
*  FUNC     :  json里增加string数据
*  ARGS     :  json             (json_object *)
*           :  p_key            (const char *)
*           :  ll_val           (long long)
*  RTN      :
*  NOTE     :  如果存在该key，则变成数组
*******************************************************************************/
FR_STATIC void __frreport_json_add_long(json_object *json, const char *p_key, long long ll_val)
{
    struct json_object *result = NULL;
    if(json == NULL ||  p_key == NULL )
        return;

    json_object_object_get_ex(json, p_key, &result);
    if(result == NULL)
    {
        json_object_object_add(json, p_key, json_object_new_int64(ll_val));
        return;
    }

    if( ! json_object_is_type(result, json_type_array)  )
    {
        json_object_get(result);
        json_object *tech=json_object_new_array();
        json_object_array_add(tech, result);
        json_object_array_add(tech,json_object_new_int64(ll_val));
        json_object_object_add(json, p_key,tech);
    }
    else
    {
        json_object_array_add(result,json_object_new_int64(ll_val));
    }

    return;
}

/*******************************************************************************
*  FUNC     :  json里增加string数据
*  ARGS     :  json             (json_object *)
*           :  p_key            (const char *)
*           :  d_val            (double)
*  RTN      :
*  NOTE     :  如果存在该key，则变成数组
*******************************************************************************/
FR_STATIC void __frreport_json_add_double(json_object *json, const char *p_key, double d_val)
{
    struct json_object *result = NULL;
    if(json == NULL ||  p_key == NULL )
        return;

    json_object_object_get_ex(json, p_key, &result);
    if(result == NULL)
    {
        json_object_object_add(json, p_key, json_object_new_double(d_val));
        return;
    }

    if( ! json_object_is_type(result, json_type_array)  )
    {
        json_object_get(result);
        json_object *tech=json_object_new_array();
        json_object_array_add(tech, result);
        json_object_array_add(tech,json_object_new_double(d_val));
        json_object_object_add(json, p_key,tech);
    }
    else
    {
        json_object_array_add(result,json_object_new_double(d_val));
    }

    return;
}

/*******************************************************************************
*  FUNC     :  l7链表信息的出力
*  ARGS     :  p_st_hdr         (Frreport_header *)
*           :  p_obj_array      (json_object *)
*           :  em_type_lst      (Frreport_type_list)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_l7data_list(Frlist_header *p_hdr, json_object *p_obj_item, Frreport_type_list em_type_lst)
{
    char arr_buff[64];
    Frlist_node *p_st_node=NULL;
    Frvar_field *p_varfield=NULL;
    Frbindata *p_st_bindata = NULL;
    json_object *p_obj_item_sub = NULL;

    if(p_hdr == NULL || frlist_size(p_hdr) <= 0 || p_obj_item == NULL)
        return;

    p_obj_item_sub = json_object_new_object();
    if(p_obj_item_sub == NULL)
        return;

    p_st_node = FRLIST_FIRST_NODE(p_hdr);
    while(p_st_node)
    {
        p_varfield =  (Frvar_field*)FRLIST_GET_NODE_DATA(p_st_node);
        if(p_varfield)
        {
            switch(p_varfield->em_data_type)
            {
                case FRLONG:
                    __frreport_json_add_long(p_obj_item_sub, p_varfield->p_field_name, p_varfield->field_value.ll_value);
                    break;
                case FRFLOAT:
                case FRDOUBLE:
                    __frreport_json_add_double(p_obj_item_sub, p_varfield->p_field_name, p_varfield->field_value.d_value);
                    break;
                case FRSTRING:
                    //json_object_object_add(p_obj_item_sub
                    //                    , p_varfield->p_field_name
                    //                    , json_object_new_string(p_varfield->field_value.p_value));
                    __frreport_json_add_str(p_obj_item_sub, p_varfield->p_field_name, p_varfield->field_value.p_value);
                    break;
                case FRBLOB:
                case FRCLOB:
                    p_st_bindata = p_varfield->field_value.p_st_value;
                    arr_buff[0] = '\0';
                    if(p_st_bindata)
                    {
                        snprintf(arr_buff, sizeof(arr_buff), "binary_len=%u", p_st_bindata->ui_len);
                    }
                    //json_object_object_add(p_obj_item_sub
                    //                    , p_varfield->p_field_name
                    //                    , json_object_new_string(arr_buff));
                    __frreport_json_add_str(p_obj_item_sub, p_varfield->p_field_name, arr_buff);
                    break;
                default:
                    break;
            }
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    switch(em_type_lst)
    {
        case FRREPORT_TYPE_LIST_REQ:
            json_object_object_add(p_obj_item, "list_request", p_obj_item_sub);
            break;
        case FRREPORT_TYPE_LIST_RESP:
            json_object_object_add(p_obj_item, "list_response", p_obj_item_sub);
            break;
        case FRREPORT_TYPE_LIST_MQ:
            json_object_object_add(p_obj_item, "list_mq", p_obj_item_sub);
            break;
        default:
            json_object_object_add(p_obj_item, "list_comm", p_obj_item_sub);
            break;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  Frreport_l7data信息的出力
*  ARGS     :  p_st_l7data      (Frreport_l7data *)
*           :  p_st_json        (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_l7data(Frreport_l7data  *p_st_l7data, json_object *p_obj_array)
{
    char arr_buff[64];
    json_object *p_obj_item = NULL;

    if(p_st_l7data == NULL || p_obj_array == NULL)
        return ;

    p_obj_item = json_object_new_object();
    if(p_obj_item == NULL)
        return;

    json_object_object_add(p_obj_item, "em_type", json_object_new_string("L7DATA"));
    json_object_object_add(p_obj_item, "ip_proto", json_object_new_int(p_st_l7data->ip_proto));
    sprintf(arr_buff, "%s", int_ntoa (p_st_l7data->src_ip));
    json_object_object_add(p_obj_item, "src_ip", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%i", p_st_l7data->src_port);
    json_object_object_add(p_obj_item, "src_port", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%s", int_ntoa (p_st_l7data->dst_ip));
    json_object_object_add(p_obj_item, "dst_ip", json_object_new_string(arr_buff));
    sprintf(arr_buff, "%i", p_st_l7data->dst_port);
    json_object_object_add(p_obj_item, "dst_port", json_object_new_string(arr_buff));
    json_object_object_add(p_obj_item, "l7_proto", json_object_new_int(p_st_l7data->i_l7_proto));

    __frreport_output_l7data_list(&p_st_l7data->st_hdr_comm, p_obj_item, FRREPORT_TYPE_LIST_COMM);
    __frreport_output_l7data_list(&p_st_l7data->st_hdr_req, p_obj_item, FRREPORT_TYPE_LIST_REQ);
    __frreport_output_l7data_list(&p_st_l7data->st_hdr_resp, p_obj_item, FRREPORT_TYPE_LIST_RESP);
    __frreport_output_l7data_list(&p_st_l7data->st_hdr_mq, p_obj_item, FRREPORT_TYPE_LIST_MQ);

    json_object_array_add(p_obj_array, p_obj_item);

    return;
}

/*******************************************************************************
*  FUNC     :  Frreport_l7data信息的出力
*  ARGS     :  p_st_body_data   (Frreport_body_data *)
*           :  p_st_json        (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_output_body(Frreport_body_data  *p_st_body_data
                                    , json_object *p_st_json, json_object *p_obj_array
                                    , int *p_i_stat_type)
{
    if(p_st_body_data == NULL || p_st_json == NULL || p_obj_array == NULL )
        return ;

    switch(p_st_body_data->em_type)
    {
        case FRREPORT_TYPE_STAT_PORT:
            *p_i_stat_type = FRREPORT_TYPE_STAT_PORT;
            __frreport_output_stat_port( &p_st_body_data->un_data.st_stat_port, p_obj_array);
            break;
        case FRREPORT_TYPE_STAT_CONN:
            *p_i_stat_type = FRREPORT_TYPE_STAT_CONN;
            __frreport_output_stat_conn( &p_st_body_data->un_data.st_stat_conn, p_obj_array);
            break;
        case FRREPORT_TYPE_L7DATA:
            *p_i_stat_type = FRREPORT_TYPE_L7DATA;
            __frreport_output_l7data( &p_st_body_data->un_data.st_l7data, p_obj_array);
            break;
        case FRREPORT_TYPE_STAT_L4:
            *p_i_stat_type = FRREPORT_TYPE_STAT_L4;
            __frreport_output_stat_tcp( &p_st_body_data->un_data.st_stat_l4_tcp, p_obj_array);
            break;
        default:
            json_object_object_add(p_st_json, "em_type", json_object_new_string("UNKNOWN"));
            break;
    }

    return;
}

char* frreport_data_output(Frreport_data *p_st_report_data, int i_flag_style)
{
    json_object *p_st_json= NULL;
    json_object *p_array=NULL;
    char *p_msg = NULL;
    Frlist_header *p_hdr_body=NULL;
    Frlist_node *p_st_node=NULL;
    Frreport_body_data *p_st_body_data=NULL;
    int i_stat_type=FRREPORT_TYPE_UNKNOWN;

    if(p_st_report_data == NULL)
        return NULL;

    p_st_json = json_object_new_object();
    if(p_st_json == NULL)
        return NULL;
    p_array = json_object_new_array();
    if(p_array == NULL)
    {
        json_object_put(p_st_json);
        return NULL;
    }

    __frreport_output_header(p_st_report_data->em_type, p_st_report_data->em_type_l7data, &p_st_report_data->st_data_header, p_st_json);

    p_hdr_body = &p_st_report_data->st_hdr_body;
    p_st_node = FRLIST_FIRST_NODE(p_hdr_body);
    while(p_st_node)
    {
        p_st_body_data =  (Frreport_body_data*)FRLIST_GET_NODE_DATA(p_st_node);
        if(p_st_body_data)
            __frreport_output_body(p_st_body_data, p_st_json, p_array, &i_stat_type);
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    json_object_object_add(p_st_json, "body_data", p_array);
    if(i_flag_style == FR_YES)
        p_msg = frstrdup(json_object_to_json_string_ext(p_st_json, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
    else
        p_msg = frstrdup(json_object_to_json_string(p_st_json));
    json_object_put(p_st_json);
    return p_msg;
}

int frreport_send(void* p_frame_ref, Frreport_data **pp_st_report_data)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;
    Report_module *p_st_report_module=NULL;
    Frreport_data *p_st_data=NULL;
    int i_ret = FR_FAIL;

    if(p_frame_ref == NULL || pp_st_report_data == NULL || *pp_st_report_data == NULL)
        goto SEND_FAIL;

    if(p_apm_context->p_st_report_moduleRef == NULL)
        goto SEND_FAIL;

    // update事件上层不处理,本应该在update事件生成处屏蔽
    // 但由于某些模块对Frreport_data参数直接取地址,会造成程序问题，故在此处过滤
    p_st_data = *pp_st_report_data;
    if(p_st_data->em_type == FRREPORT_TYPE_L7DATA && p_st_data->em_type == FRREPORT_TYPE_L7DATA_UPDATE)
    {
        if(pp_st_report_data && *pp_st_report_data )
            frreport_data_free(pp_st_report_data);
        return FR_SUCC;
    }

    p_st_report_module = (Report_module *)(p_apm_context->p_st_report_moduleRef);
    i_ret = p_st_report_module->add_data(pp_st_report_data);

    if(pp_st_report_data && *pp_st_report_data)
        frreport_data_free(pp_st_report_data);
    return i_ret;

SEND_FAIL:
    if(pp_st_report_data && *pp_st_report_data )
        frreport_data_free(pp_st_report_data);
    return FR_FAIL;
}

